#ifndef _imageFuncs1_h_
#define _imageFuncs1_h_

// imageFuncs1.h
//
// non-member image functions that take 1 image argument

#include "image/imageTmpl.h"
#include "image/imageTools.h"

#include <typeinfo>

namespace simple{
    //
    // copy
    //
    // copy always does a pixel by pixel copy. This version
    // makes no assumptions about the type of T1 or T2. The next 
    // version, copyfast, makes the assumption that memcpy 
    // can be used to duplicate pixels (if T1 == T2).
    template<class R, class T1, class T2, class S1, class S2>
    void _copy (const R&, const Image<T1,S1>& src1, Image<T2,S2>& dst1)
    {
        typename Image<T1,S1>::row_iterator i1;
        typename Image<T2,S2>::row_iterator i2;
        unsigned int w = src1.width ();
        const T1* p1;
        T2* p2;
        for (i1=src1.row_begin(), i2=dst1.row_begin();
             i1 != src1.row_end(); i1++, i2++) {
            p1 = i1->p;
            p2 = i2->p;
            for (unsigned int x=0; x<w; x++)
                *p2++ = static_cast<T2>(*p1++);
        }
    }


    template<class R, class T1, class T2, class S1, class S2>
    void _copyfast (const R&, const Image<T1,S1>& src1, Image<T2,S2>& dst1)
    {
        typename Image<T1,S1>::row_iterator i1 = src1.row_begin();
        typename Image<T2,S2>::row_iterator i2 = dst1.row_begin();
        unsigned int w = src1.width();
        unsigned int bytes = w * src1.bytesPerPixel ();
        const T1* p1;
        T2* p2;

        if (typeid(T1) == typeid(T2)) {
            // We're copying like datatypes so use memcpy for speed
            // This assumes T1 and T2 are POD (plain old data) types
            for (; i1 != src1.row_end(); i1++, i2++) {
                p1 = i1->p;
                p2 = i2->p;
                memcpy (p2, p1, bytes);
            }
        }
        else {
            // We have to do a pixel by pixel copy
            for (; i1 != src1.row_end(); i1++, i2++) {
                p1 = i1->p;
                p2 = i2->p;
                for (unsigned int x=0; x<w; x++)
                    *p2++ = static_cast<T2>(*p1++);
            }
        }
    }

    template<class T1, class S1, class T2, class S2>
    void copy (const Image<T1,S1>& src, Image<T2,S2>& dst)
    {
        Function_s1d1<T2,T1,T2,S1,S2> processor (_copy);
        processor.run (src, dst);
    }

    template<class T1, class S1>
    Image<T1,S1> copy (const Image<T1,S1>& src)
    {
        // Assume we can use memcpy if possible.
        Image<T1,S1> dst;

        Function_s1d1<T1,T1,T1,S1,S1> processor (_copyfast);
        processor.run (src, dst);

        return dst;
    }

    // If you are curious about how the above version of copy() can
    // be written using the STL way, here is a version that does it.
    // Since we do not have input iterators in images, you must
    // allocate the destination and then use std::copy.
    template<class T1, class S1>
    Image<T1,S1> copy_stl (const Image<T1,S1>& src)
    {
        ImageLocker<T1,S1> srcLocking (src);

        Image<T1,S1> dst (src.boundary(), src.alignment());
        std::copy (src.begin(), src.end(), dst.begin());

        return dst;
    }

    //
    // duplicate
    //
    template<class T1, class S1>
    Image<T1,S1> duplicate (const Image<T1,S1>& src, 
                              RectImageStorage::eAlignment align)
    {
        if (src.isNull())
            return src;

        Image<T1,S1> dst (src.boundary(), align);

        Function_s1d1<T1,T1,T1,S1,S1> processor (copyfast);
        processor.run (src, dst);

        return dst;
    }

}


#endif // _imageFuncs1_h_
